/*
 * Created on Feb 17, 2005
 * Created by dfhuynh
 */
package edu.mit.simile.longwell.query.project;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.hp.hpl.jena.rdf.model.Resource;

import edu.mit.simile.longwell.Cache;

/**
 * @author dfhuynh
 */
public abstract class ProjectionBase implements IProjection {
	final protected String	m_locale;
	final protected Cache	m_objectToValueCache;
	final protected Cache	m_valueToObjectsCache;
	final protected Cache	m_valuesToObjectsCache;
	protected Set			m_values;
	protected Map			m_objectToValueMap;

	protected ProjectionBase(String locale) {
		m_locale = locale != null ? locale : "";
		m_objectToValueCache = new Cache(1000, ProjectionBase.class, "object-to-value");
		m_valueToObjectsCache = new Cache(100, ProjectionBase.class, "value-to-objects");
		m_valuesToObjectsCache = new Cache(10, ProjectionBase.class, "values-to-objects");
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.IProjection#getValues()
	 */
	public Set getValues() {
		if (m_values == null) {
			Map m = getObjectToValueMap();
			
			m_values = new HashSet();
			
			Set objects = getObjects();
			
			if (objects.size() < m.size()) {
				Iterator i = objects.iterator();
				while (i.hasNext()) {
					m_values.add(m.get((Resource) i.next()));
				}
			} else {
				Iterator i = m.keySet().iterator();
				while (i.hasNext()) {
					if (!objects.contains(i.next())) {
						i.remove();
					}
				}
				m_values.addAll(m.values());
			}
		}
		return m_values;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.IProjection#getValue(com.hp.hpl.jena.rdf.model.Resource)
	 */
	public Object getValue(Resource object) {
		Object value = m_objectToValueCache.get(object);
		if (value == null) {
			value = internalGetValue(object);
			m_objectToValueCache.put(object, value);
		}
		return value;
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjection#countObjects()
	 */
	public int countObjects() {
		return getObjects().size();
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.IProjection#getObjects(java.lang.Object)
	 */
	public Set getObjects(Object value) {
		Set objects = (Set) m_valueToObjectsCache.get(value);
		if (objects == null) {
			objects = internalGetObjects(value);
			m_valueToObjectsCache.put(value, objects);
		}
		return objects;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjection#countObjects(java.lang.Object)
	 */
	public int countObjects(Object value) {
		return getObjects(value).size();
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.IProjection#getObjects(java.util.Set)
	 */
	public Set getObjectsWithValues(Set values) {
		Set objects = (Set) m_valuesToObjectsCache.get(values);
		if (objects == null) {
			objects = new HashSet();
			
			Iterator i = values.iterator();
			while (i.hasNext()) {
				objects.addAll(getObjects(i.next()));
			}
			
			m_valuesToObjectsCache.put(values, objects);
		}		
		return objects;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjection#countObjects(java.util.Set)
	 */
	public int countObjectsWithValues(Set values) {
		return getObjectsWithValues(values).size();
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjection#getObjectToValueMap()
	 */
	public Map getObjectToValueMap() {
		if (m_objectToValueMap == null) {
			m_objectToValueMap = internalGetObjectToValueMap();
		}
		return m_objectToValueMap;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjection#getLocale()
	 */
	public String getLocale() {
		return m_locale;
	}

	
	abstract protected Object internalGetValue(Resource object);
	
	abstract protected Set internalGetObjects(Object value);
	
	abstract protected Map internalGetObjectToValueMap();
	
}
